package com.newlink.building.login.ui

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.text.*
import android.text.method.LinkMovementMethod
import android.text.style.ForegroundColorSpan
import android.util.Log
import android.view.*
import android.widget.PopupWindow
import android.widget.ScrollView
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.TooltipCompat
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.widget.addTextChangedListener
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.alibaba.sdk.android.push.CommonCallback
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory
import com.google.android.material.tabs.TabLayout
import com.newlink.building.login.utils.Module_Login_AccountMemoryUtils
import com.newlink.building.login.BuildConfig
import com.newlink.building.login.R
import com.newlink.building.login.common.Module_Login_CheckUrlBean
import com.newlink.building.login.common.Module_Login_Constant.ACCOUNT_PASSWORD_LOGIN
import com.newlink.building.login.common.Module_Login_Constant.SIP_PASSWORD_LOGIN
import com.newlink.building.login.common.widget.Module_Login_EnvChoiceDialog
import com.newlink.building.login.databinding.ActivityLoginBinding
import com.newlink.building.login.event.SetKitPwdEvent
import com.newlink.building.login.mvp.contract.Module_Login_LoginContract
import com.newlink.building.login.widget.Module_Login_PolicyClickableSpan
import com.newlink.building.login.widget.Module_Login_UserClickableSpan
import com.newlink.building.common_base.activities.NL_WebViewActivityNL
import com.newlink.building.common_base.base.BaseApplication
import com.newlink.building.common_base.base.BaseApplication.Companion.getCurrentCountryLanguage
import com.newlink.building.common_base.base.NL_BaseMvpActivity
import com.newlink.building.common_base.base.NL_OnActivityCallback
import com.newlink.building.common_base.constant.*
import com.newlink.building.common_base.constant.Base_Constant.LOGIN_EXTRA_ACTION_CONFLICT
import com.newlink.building.common_base.constant.Base_Constant.LOGIN_EXTRA_ACTION_MSG_TIMEOUT
import com.newlink.building.common_base.event.MessageEvent
import com.newlink.building.common_base.event.TYPE_APP_EXIT
import com.newlink.building.common_base.event.TYPE_REGISTER_SUCCESS
import com.newlink.building.common_base.ext.showToast
import com.newlink.building.common_base.ext.showToastImmediately
import com.newlink.building.common_base.http.Base_RetrofitHelper
import com.newlink.building.common_base.manager.Base_CountryCodeManager
import com.newlink.building.common_base.model.bean.*
import com.newlink.building.common_base.utils.*
import com.newlink.building.common_base.utils.countrycode.Base_CountryCodeSelectActivityNL
import com.newlink.building.common_base.widget.CustomMessageDialog
import com.newlink.building.common_base.widget.SpaceItemDecoration
import com.newlink.building.common_base.widget.ToastSettingDialog
import com.newlink.building.crypt.library_crypt.digest.Md5Crypt
import com.newlink.building.utils.Module_Phone_Base64Utils
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationHelper
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationInvoker
import com.newlink.building.login.adapter.Module_Login_AccountPickAdapter
import com.newlink.building.login.bean.UserAccountInfo
import com.newlink.building.login.bean.UserCategoryInfo
import com.newlink.building.login.mvp.presenter.Module_Login_LoginPresenter
import com.newlink.building.login.widget.Module_Login_AnimatedCategoryPopupWindow
import com.newlink.building.login.utils.Module_Login_KeyboardUtils
import com.tencent.bugly.crashreport.CrashReport
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.jetbrains.anko.singleLine
import org.jetbrains.anko.textColor
import org.json.JSONArray
import com.newlink.building.common_base.utils.EnhancedLogger

/**
 * Created by xiaodong on 2022/8/11.
 */
@Route(path = Base_RouterPath.PATH_LOGIN)
class Module_Login_LoginActivityNL : NL_BaseMvpActivity<Module_Login_LoginContract.View, Module_Login_LoginContract.Presenter>(),
    Module_Login_LoginContract.View {

    companion object {
        private const val DEFAULT_PWD_PLACEHOLDER: String = "f@n7!L*P@sS2v0rD"
        private const val FLS_REGION_DEFAULT_FILE_PATH: String = "fls_region_default.json"
    }

    private var mWayToLogin = ACCOUNT_PASSWORD_LOGIN
    private var needSavePwd = false
    private var mEmailAccount: String = ""
    private var mPwdValue: String = ""
    private var tabAccount: TabLayout.Tab? = null
    private var tabPhoneNum: TabLayout.Tab? = null
    private var mAccountSeleted = true
    private var appCfgProgress: Boolean = false
    private var mQRCodeLogin = false
    private var mDefaultCountryCodeBean: CountryCodeBean? = null
    private var mModuleLoginCheckUrlBeans = mutableListOf<Module_Login_CheckUrlBean>()

    private lateinit var mBinding: ActivityLoginBinding
    private var spannableString: SpannableStringBuilder? = null
    private var clickableSpan: Module_Login_CustomClickableSpan? = null
    private var mLoginDataFromRegister: LoginResponseData? = null
    private var mPolicyAgreementData: PolicyAgreementData? = null
    private var mSelectCategory: UserCategoryInfo? = null

    private val userClickableSpan: Module_Login_UserClickableSpan by lazy {
        Module_Login_UserClickableSpan(this)
    }
    private val policyClickableSpan: Module_Login_PolicyClickableSpan by lazy {
        Module_Login_PolicyClickableSpan(this)
    }

    private var userAccountInfoList: MutableList<UserAccountInfo> by Base_Preference(
        Base_Constant.USER_ACCOUNT_INFO_LIST_KEY,
        mutableListOf(UserAccountInfo("", "", "", "", 0L, 1))
    )

    private val mDialog by lazy {
        DialogUtil.getWaitDialog(this)
    }

    private var categoryList = mutableListOf<UserCategoryInfo>()
    private var scrollView: ScrollView? = null

    override fun attachLayoutRes(): View {
        mBinding = ActivityLoginBinding.inflate(layoutInflater)
        return mBinding.root
    }

    override fun createPresenter() = Module_Login_LoginPresenter()

    override fun initData() {
        //兼容老版本,升级后serialVersionUID变化会导致序列号失败,需要重新移除key
        ifNeedClearPreference()
        lifecycle.addObserver(userClickableSpan)
        lifecycle.addObserver(policyClickableSpan)

        // 首次安装时自动设置默认地址，避免第一次登录请求失败
        initDefaultApiUrl()

        loadDefaultCountryCode()
        loadFlsServerList()
        loadPolicyAndAgreement()

        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.POST_NOTIFICATIONS
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // Request the permission
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
        if (intent.action == Base_Constant.ACCOUNT_INFORMATION_CHANGE_PASSWORD) {
            mEmailAccount = emailAccount
            saveAccountInfo()
        }
        initCategoryList()
    }

    /**
     * 初始化默认API地址
     * 首次安装时自动设置为BASE_XLINK_URL，避免用户第一次登录请求失败
     */
    private fun initDefaultApiUrl() {
        // 检查是否是首次使用且API地址未设置
        if (isFirstUse && api_env_url.isEmpty()) {
            NLog.e("[LoginActivity] 首次安装，自动设置默认地址: ${Base_Constant.BASE_XLINK_URL}")

            // 设置为默认地址
            api_env_url = Base_Constant.BASE_XLINK_URL
            api_env_url_custom = Base_Constant.BASE_XLINK_URL  // 同时设置自定义地址
            // api_env 将在服务器列表加载完成后设置为自定义选项的索引

            // 更新BASE_URL
            Base_Constant.BASE_URL = api_env_url

            // 刷新网络配置
            Base_RetrofitHelper.refreshDynamicBaseUrl()

            // 标记首次使用已完成
            isFirstUse = false

            NLog.e("[LoginActivity] 默认地址设置完成，使用自定义地址: $api_env_url")
        }
    }

    private fun initCategoryList() {
        categoryList.add(UserCategoryInfo(getString(R.string.login_end_user), 1))
        categoryList.add(UserCategoryInfo(getString(R.string.login_property_manager), 3))
        if (mSelectCategory == null) {
            categoryList.forEach {
                if (it.category == userCategory) {
                    mSelectCategory = it
                }
            }
            initDefaultUserCategory()
        }
    }

    private fun ifNeedClearPreference() {
        val shareKeys = mutableListOf(
            Base_Constant.USER_INFO_KEY,
            Base_Constant.MQTT_INFO_KEY,
            Base_Constant.USER_INFO_RESP_KEY,
            Base_Constant.COUNTRY_DEFAULT,
            Base_Constant.COUNTRY_LIST
        )
        shareKeys.forEach { key ->
            if (Base_Preference.contains(key)) {
                Base_Preference.clearPreference(key)
            }
        }
    }

    private fun loadFlsServerList() {
        val language = getCurrentCountryLanguage()
        NLog.e("[LoginActivity] >>> loadFlsServerList 开始加载服务器列表, language=$language")
        mPresenter?.getFcmsInfoList("region", language)
//        if (useExtra()) {
//            mCheckUrlBeans?.add(CheckUrlBean("其他", flsServer, 0, true))
//        }

        // load fls server list from fdps server
    }

    private fun loadPolicyAndAgreement() {
        mPresenter?.getAgreement()
    }

    private fun useExtra(): Boolean {
        if (mModuleLoginCheckUrlBeans != null && flsServer.isNotEmpty()) {
            for (k in mModuleLoginCheckUrlBeans!!) {
                if (k.url == flsServer) {
                    return false
                }
            }
        }
        return true
    }

    private fun loadDefaultCountryCode() {
        if (countryCode.isEmpty()) {
            mDefaultCountryBean = Base_CountryCodeManager.getDefaultCountryCode(applicationContext)
            countryCode = mDefaultCountryBean.code
        }

    }

    override fun initView() {
        super.initView()
        setupKeyboardHandling()
        mBinding.countryCodeBtn.text = "+ $countryCode"

        mBinding.countryCodeBtn.setOnClickListener {
            val intent = Intent(this, Base_CountryCodeSelectActivityNL::class.java)
            startActivityForResult(
                intent,
                object : NL_OnActivityCallback {
                    @SuppressLint("SetTextI18n")
                    override fun onActivityResult(resultCode: Int, data: Intent?) {
                        if (resultCode == 1_000_008) {
                            val defaultCountryCode = data?.getStringExtra("default_country_code")
                            if (defaultCountryCode?.isNotEmpty() == true) {
                                mBinding.countryCodeBtn.text = "+ $defaultCountryCode"
                                countryCode = defaultCountryCode
                            }
                        }
                    }
                })

        }


        if (BuildConfig.DEBUG) {
//            mBinding.tvPhoneRegister.visibility = View.VISIBLE
        }

        mBinding.tvPhoneRegister.setOnClickListener {
            ARouter.getInstance().build(Base_RouterPath.PATH_REGISTER).navigation()
        }

        mBinding.userBtnRegister.setOnClickListener {
//            jumpToRegister()
        }

        mBinding.btnLogin.setOnClickListener {
            mQRCodeLogin = false
            excLogin()
        }

        mBinding.scan.setOnClickListener {
            if (!PermissionHelper.required(this).hasPermission(Manifest.permission.CAMERA)) {
                checkCameraPermission()
//                requestPermissions(arrayOf(Manifest.permission.CAMERA), 0)
            } else {
                jumpToCapture()
            }

        }

        TooltipCompat.setTooltipText(mBinding.tabLoginTitle, "")
//        mBinding.tabLoginTitle.tabRippleColor = resources.getColor(R.color.transparent_color , null)
        tabAccount = mBinding.tabLoginTitle.getTabAt(0)
        tabPhoneNum = mBinding.tabLoginTitle.getTabAt(1)

        initTabLayout()


        setSpannableStringView(
//            this@LoginActivity,
            BaseApplication.context,
            mBinding.licenseContent,
            getString(R.string.user_register_license_user),
            getString(R.string.user_register_license_privacy),
            getString(R.string.user_register_license1)
        )

//        mBinding.etLoginPhoneNum.setBackgroundResource(R.drawable.et_underline_selector)
//        mBinding.etPasswordSip.setBackgroundResource(R.drawable.et_underline_selector)
        mBinding.etLoginPhoneNum.addTextChangedListener {
            mBinding.btnSendVerify.isEnabled = it.toString().isNotEmpty()
        }

        mBinding.btnSendVerify.setOnClickListener {
            // 判断手机号是否符合规格
//            if (!RegexUtils.checkMobile(verifyPhone)) {
//                verify_phone_layout.error = resources.getString(R.string.regex_phone_error_format)
//                return@setOnClickListener
//            }
            mPresenter?.getVerifyCode(countryCode, getVerifyPhone(), mSelectCategory!!.category)
        }
        mBinding.cbLoginAgreeLicense.setOnCheckedChangeListener { _, value ->
            if (value) {
                mBinding.cbLoginAgreeLicense.error = null
            }
            updateLoginBtnState()
        }
        mBinding.cbLoginAgreeLicense.setOnClickListener {
            if (!TextUtils.isEmpty(mBinding.cbLoginAgreeLicense.error)) {
                mBinding.cbLoginAgreeLicense.error =
                    resources.getString(R.string.user_reset_email_error_licenses)
            }
        }
        mBinding.tvForgetPwd.setOnClickListener {
            Intent(this, Module_Login_ForgetPwdEmailActivityNL::class.java).apply {
                putExtra(Base_Constant.KEY_USER_CATEGORY, mSelectCategory?.category)
                startActivity(this)
            }
        }
//        initFCM()

        // 使用增强日志记录 Intent action
        EnhancedLogger.userAction(
            tag = "LoginActivity",
            action = "ACTIVITY_STARTED",
            details = "Intent action: ${intent?.action}"
        )

        if (intent?.action.equals(LOGIN_EXTRA_ACTION_CONFLICT)) {
            if (isFinishing || isDestroyed) {
                return
            }
//                .tittle(getString(R.string.login_conflict_title))
            ToastSettingDialog.Builder(this)
                .drawable(R.drawable.toast_warning_yellow)
                .message(resources.getString(R.string.login_conflict)).build().apply {
                    show()
                }
        } else if (intent?.action.equals(LOGIN_EXTRA_ACTION_MSG_TIMEOUT)) {
            if (isFinishing || isDestroyed) {
                return
            }
//                .tittle(getString(R.string.login_conflict_title))
            ToastSettingDialog.Builder(this)
                .drawable(R.drawable.toast_warning_yellow)
                .message(resources.getString(R.string.login_information_timeout)).build().apply {
                    show()
                }
        }

        //DEBUG模式下,登录需要手动配置fls地址
        if (!isLogin) {
            var selectIndex = 0
            mBinding.tvSelectAddress.visibility = View.VISIBLE

            // 初始显示：如果是首次安装或使用自定义地址，显示"自定义"
            if (api_env_url.isNotEmpty()) {
                // 先设置一个默认显示，等服务器列表加载完成后会更新
                mBinding.tvSelectAddress.text = getString(R.string.login_region_custom_fcms_title)
            }

            mBinding.tvSelectAddress.setOnClickListener {

                selectIndex = api_env
                val dialog = Module_Login_EnvChoiceDialog(this)
                dialog.setCheckBeans(mModuleLoginCheckUrlBeans)
                    .setSelectedPostion(selectIndex)
                    .setNegativeButton(object : Module_Login_EnvChoiceDialog.OnClickListener {
                        override fun onClick(bean: Module_Login_CheckUrlBean, position: Int) {
                            dialog.dismiss()
                        }

                    }).setPositiveButton(object : Module_Login_EnvChoiceDialog.OnClickListener {
                        override fun onClick(bean: Module_Login_CheckUrlBean, position: Int) {

                            NLog.e("checkURL  ${RegexUtils.checkURL(bean.url)}")
                            if (bean.url.isNullOrEmpty() || !RegexUtils.checkURL(bean.url)) {
                                showToast(getString(R.string.login_select_address_incorrect))
                                return
                            }
//                            if(!bean.url.endsWith("/")){
//                                bean.url = bean.url.plus("/")
//                            }
                            if (bean.type == 1) {
                                api_env_url_custom = bean.url
                            }
                            api_env_url = bean.url
                            api_env = position
                            Base_Constant.BASE_URL = api_env_url
                            showToast("$api_env_url")
                            Base_RetrofitHelper.refreshDynamicBaseUrl()
                            mBinding.tvSelectAddress.text = bean.displayName

                            dialog.dismiss()
                        }

                    }).show()
            }
        }
        mBinding.imagePickAccount.setOnClickListener {
            showPopupWindow()
        }

        mBinding.linearCategoryAccount.setOnClickListener {
            showUserCategoryPopupWindow(mBinding.linearCategoryAccount)
        }

        mBinding.linearCategoryVia.setOnClickListener {
            showUserCategoryPopupWindow(mBinding.linearCategoryVia)
        }

        mBinding.etUsername.addTextChangedListener {
            updateLoginBtnState()
        }
        
        mBinding.etUsername.setOnFocusChangeListener { v, hasFocus ->
            if (hasFocus) {
                scrollToView(v)
            }
        }

        mBinding.etPassword.addTextChangedListener {
            updateLoginBtnState()
        }
        
        mBinding.etPassword.setOnFocusChangeListener { v, hasFocus ->
            if (hasFocus) {
                scrollToView(v)
            }
        }

        mBinding.etLoginPhoneNum.addTextChangedListener {
            updateLoginBtnState()
        }
        
        mBinding.etLoginPhoneNum.setOnFocusChangeListener { v, hasFocus ->
            if (hasFocus) {
                scrollToView(v)
            }
        }

        mBinding.etPasswordSip.addTextChangedListener {
            updateLoginBtnState()
        }
        
        mBinding.etPasswordSip.setOnFocusChangeListener { v, hasFocus ->
            if (hasFocus) {
                scrollToView(v)
            }
        }

        updateLoginBtnState()
    }

    private fun updateLoginBtnState() {
        if (mAccountSeleted) {
            mBinding.btnLogin.isEnabled =
                !mBinding.etUsername.text.isNullOrEmpty() && !mBinding.etPassword.text.isNullOrEmpty() && mBinding.cbLoginAgreeLicense.isChecked
        } else {
            mBinding.btnLogin.isEnabled =
                !mBinding.etLoginPhoneNum.text.isNullOrEmpty() && !mBinding.etPasswordSip.text.isNullOrEmpty() && mBinding.cbLoginAgreeLicense.isChecked
        }
    }

    private fun parseFcmsInfoFromAssets(): MutableList<FcmsInfoData> {
        val fcmsInfoDatas = mutableListOf<FcmsInfoData>()
        val regionText =
            assets.open(FLS_REGION_DEFAULT_FILE_PATH).bufferedReader(Charsets.UTF_8).readText()
        val regionArray = JSONArray(regionText)
        for (index in 0 until regionArray.length()) {
            val jsonObject = regionArray.getJSONObject(index)
            val id = jsonObject.optInt("id", 0)
            val url = jsonObject.getString("url")
            val name = jsonObject.getString("name")
            fcmsInfoDatas.add(FcmsInfoData(id, url, name))
        }
        return fcmsInfoDatas
    }

    private fun parseCustomRegionBean(): Module_Login_CheckUrlBean {
        val customUrl = if (api_env_url_custom.isEmpty()) "http://" else api_env_url_custom
        return Module_Login_CheckUrlBean(
            -1,
            getString(R.string.login_region_custom_fcms_title),
            customUrl,
            1,
            false
        )
    }

    private fun initDefaultUserCategory() {
        mSelectCategory?.let {
            mBinding.tvCategoryAccount.text = it.username
            mBinding.tvCategoryVia.text = it.username
        }
    }

    private fun initUserCategory(category: Int) {
        categoryList.forEach {
            if (it.category == category) {
                mSelectCategory = it
            }
        }
        mSelectCategory?.let {
            mBinding.tvCategoryAccount.text = it.username
            mBinding.tvCategoryVia.text = it.username
        }
    }

    private fun showUserCategoryPopupWindow(dropView: View) {
        val animatedPopup = Module_Login_AnimatedCategoryPopupWindow(
            context = this,
            categoryList = categoryList,
            onItemSelected = { selectedCategory ->
                mSelectCategory = selectedCategory
                mBinding.tvCategoryAccount.text = selectedCategory.username
                mBinding.tvCategoryVia.text = selectedCategory.username
                
                // Add a subtle animation to the text views when selection changes
                animateTextChange(mBinding.tvCategoryAccount)
                animateTextChange(mBinding.tvCategoryVia)
            }
        )
        
        animatedPopup.showAnimated(dropView)
    }
    
    private fun animateTextChange(textView: TextView) {
        textView.animate()
            .scaleX(0.95f)
            .scaleY(0.95f)
            .setDuration(100)
            .withEndAction {
                textView.animate()
                    .scaleX(1f)
                    .scaleY(1f)
                    .setDuration(100)
                    .start()
            }
            .start()
    }
    
    private fun setupKeyboardHandling() {
        // Find the ScrollView in the layout
        scrollView = findViewById(R.id.login_scroll_view)
        
        // Setup keyboard listener with auto-scroll
        Module_Login_KeyboardUtils.setupKeyboardHandling(this, scrollView)
    }
    
    private fun scrollToView(view: View) {
        scrollView?.post {
            val scrollTo = getRelativeTop(view)
            scrollView?.smoothScrollTo(0, scrollTo - 200)
        }
    }
    
    private fun getRelativeTop(child: View): Int {
        var offsetTop = 0
        var currentView: View? = child
        
        while (currentView != null && currentView != scrollView) {
            offsetTop += currentView.top
            currentView = currentView.parent as? View
        }
        
        return offsetTop
    }

    private fun showPopupWindow() {
        val popupWindow = PopupWindow(this)
        val view: View = LayoutInflater.from(this).inflate(R.layout.popup_account_pick, null)
        var recyclerView = view.findViewById<RecyclerView>(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.addItemDecoration(SpaceItemDecoration(this))
        val accountList = if (Module_Login_AccountMemoryUtils.checkUserAccountEmpty(userAccountInfoList)) {
            mutableListOf()
        } else userAccountInfoList
        if (accountList.isEmpty() || (accountList.size == 1 && accountList[0].timestamp == 0L)) {
            return
        }
        val accountPickAdapter = Module_Login_AccountPickAdapter(accountList)
        recyclerView.adapter = accountPickAdapter
        accountPickAdapter.setOnItemChildClickListener { _, _, position ->
            emailAccount = accountList[position].username
            pwdSaved = accountList[position].pwd
            mBinding.etUsername.setText(accountList[position].username)
            mBinding.etPassword.setText(DEFAULT_PWD_PLACEHOLDER)
            initUserCategory(accountList[position].userCategory)
            popupWindow.dismiss()
        }

        popupWindow.width = mBinding.linearUsernameLayout.width
        popupWindow.height = ViewGroup.LayoutParams.WRAP_CONTENT
        popupWindow.contentView = view
        popupWindow.isFocusable = true
        popupWindow.setBackgroundDrawable(ColorDrawable(getColor(R.color.grey100)))
        popupWindow.elevation = 5f
        popupWindow.showAsDropDown(mBinding.linearUsernameLayout)
    }

    private fun initTabLayout() {

        for (i in 0 until mBinding.tabLoginTitle.tabCount) {
            mBinding.tabLoginTitle.getTabAt(i)?.view?.isLongClickable = false
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                mBinding.tabLoginTitle.getTabAt(i)?.view?.tooltipText = null
            }
        }

        tabAccount?.let {
            it.view.apply {
                setOnClickListener {
                    mAccountSeleted = true
                    switchLoginMethod(ACCOUNT_PASSWORD_LOGIN)
                }
            }
        }
        tabPhoneNum?.let {
            it.view.apply {
                setOnClickListener {
                    mAccountSeleted = false
                    switchLoginMethod(SIP_PASSWORD_LOGIN)
                }
            }
        }
        mBinding.tvLoginCheckTypeBtn.setOnClickListener {
            if (mWayToLogin == ACCOUNT_PASSWORD_LOGIN) {
                mAccountSeleted = false
                switchLoginMethod(SIP_PASSWORD_LOGIN)
            } else {
                mAccountSeleted = true
                switchLoginMethod(ACCOUNT_PASSWORD_LOGIN)
            }
        }

        val onGlobalLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                mBinding.tabLoginTitle.viewTreeObserver.removeOnGlobalLayoutListener(this)
                for (i in 0 until mBinding.tabLoginTitle.tabCount) {
                    mBinding.tabLoginTitle.getTabAt(i)!!.view.isLongClickable = false
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        mBinding.tabLoginTitle.getTabAt(i)!!.view.tooltipText = null
                    }
                }
            }
        }
        mBinding.tabLoginTitle.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)

        switchTabItem()
        mBinding.loginTypeTitle.text = getString(R.string.account_password_login)
        mBinding.tvLoginCheckTypeBtn.text = getString(R.string.sip_password_login)
    }

    private fun switchTabItem() {
        setTabItem(tabAccount!!, mAccountSeleted)
        setTabItem(tabPhoneNum!!, !mAccountSeleted)
    }

    private fun setTabItem(tab: TabLayout.Tab, isSelect: Boolean) {
        tab.customView = null
        val tv = TextView(this@Module_Login_LoginActivityNL)
        tv.text = tab.text
        tv.paint.isFakeBoldText = isSelect
        tv.paint.color = if (isSelect) resources.getColor(R.color.tab_item_selected_color)
        else resources.getColor(R.color.grey)
        tv.textColor = if (isSelect) resources.getColor(R.color.tab_item_selected_color)
        else resources.getColor(R.color.grey)
        tv.singleLine = true
        tv.textSize = if (isSelect) 22F else 18F
        tab.customView = tv
    }

    private fun excLogin() {
        // 登录方法开始时混淆
        Module_Obfuscation_ObfuscationHelper.onMethodEnter("LoginActivity", "excLogin")

        // 对登录方式进行混淆
        Module_Obfuscation_ObfuscationInvoker.invokeRandom(mWayToLogin)

        when (mWayToLogin) {
            ACCOUNT_PASSWORD_LOGIN -> {
                if (api_env_url.isEmpty()) {
                    showToast(getString(R.string.login_select_address_first))
                    return
                }
                val userName = mBinding.etUsername.text.toString().trim()
                val passWord = mBinding.etPassword.text.toString().trim()

                // 对用户名和密码进行混淆处理（不改变原值）
                Module_Obfuscation_ObfuscationHelper.beforeNetworkRequest(userName, mapOf("type" to "login"))
                Module_Obfuscation_ObfuscationInvoker.invokeSpecific(8, passWord)

                NLog.e("[LoginActivity]登陆 : userName is $userName")
                NLog.e("[LoginActivity]登陆 : passWord is $passWord")

                if (!mBinding.cbLoginAgreeLicense.isChecked) {
                    mBinding.cbLoginAgreeLicense.error =
                        getString(R.string.login_error_agree_license)
                    showToastImmediately(getString(R.string.user_reset_email_error_licenses))
                    return
                }
                mEmailAccount = userName
                mPwdValue = passWord

                if (emailAccount.isNotEmpty() && pwdSaved.isNotEmpty()) {
                    //检查邮箱或用户名是否为已登录账号
                    if (checkIfEmailOrUserIdExists(mEmailAccount) && passWord == DEFAULT_PWD_PLACEHOLDER) {
//                        NLog.e("[LoginActivity] 登陆Action 1 --> 用户名 = $userName 密码 =  $pwdSaved <不用加密>")
                        mPresenter?.loginFls(userName, pwdSaved, mSelectCategory!!.category, false)
                        return
                    }
                    if (mEmailAccount == emailAccount && passWord == DEFAULT_PWD_PLACEHOLDER) {
//                        NLog.e("[LoginActivity] 登陆Action 1 --> 用户名 = $userName 密码 =  $pwdSaved <不用加密>")
                        mPresenter?.loginFls(userName, pwdSaved, mSelectCategory!!.category, false)
                        return
                    }
                }
//                NLog.e("[LoginActivity] 登陆Action 2 --> 用户名 = $userName 密码 =  $passWord <需要加密>")
                mPresenter?.loginFls(userName, passWord, mSelectCategory!!.category, true)

            }

            SIP_PASSWORD_LOGIN -> {
                if (TextUtils.isEmpty(getVerifyPhone())) {
//                    mBinding.verifyPhoneLayout.error = getString(R.string.login_error_username_null)
                    return
                }
                if (TextUtils.isEmpty(getVerifyCode())) {
//                    mBinding.verifyCodeLayout.error = getString(R.string.login_error_password_null)
                    return
                }
                if (!mBinding.cbLoginAgreeLicense.isChecked) {
                    mBinding.cbLoginAgreeLicense.error =
                        getString(R.string.login_error_agree_license)
                    showToastImmediately(getString(R.string.user_reset_email_error_licenses))
                    return
                }
                mPresenter?.loginFlsMsgCode(
                    countryCode,
                    getVerifyPhone(),
                    getVerifyCode(),
                    mSelectCategory!!.category
                )
            }
        }
    }

    fun getVerifyPhone(): String {
        return mBinding.etLoginPhoneNum.text.toString()
    }

    fun getVerifyCode(): String {
        return mBinding.etPasswordSip.text.toString()
    }

    private fun switchLoginMethod(wayToLogin: Int) {

        Log.e("TAG", "setTabItem: ${wayToLogin}")
        hideLoginLayout()
        when (wayToLogin) {
            ACCOUNT_PASSWORD_LOGIN -> {
                mBinding.namePasswordLayout.visibility = View.VISIBLE
                mBinding.tvForgetPwd.visibility = View.VISIBLE
                mBinding.loginTypeTitle.text = getString(R.string.account_password_login)
                mBinding.tvLoginCheckTypeBtn.text = getString(R.string.sip_password_login)
            }

            SIP_PASSWORD_LOGIN -> {
                mBinding.phoneVerifyLayout.visibility = View.VISIBLE
                mBinding.tvForgetPwd.visibility = View.INVISIBLE
                mBinding.loginTypeTitle.text = getString(R.string.sip_password_login)
                mBinding.tvLoginCheckTypeBtn.text = getString(R.string.account_password_login)
            }
        }
        mWayToLogin = wayToLogin
        switchTabItem()
        updateLoginBtnState()
    }

    private fun hideLoginLayout() {
        mBinding.namePasswordLayout.visibility = View.GONE
        mBinding.phoneVerifyLayout.visibility = View.GONE
    }

    private fun jumpToCapture() {
        val intent = Intent(this, Module_Login_ScanActivityNL::class.java)
        startActivityForResult(intent, 100)
    }

    private fun jumpToRegister(json: String) {
        val intent = Intent(this, Module_Login_RegisterActivityNL::class.java).run {
            putExtra("kit_device_data", json)
        }
        startActivity(intent)
    }

    override fun hideLoading() {
        if (!appCfgProgress) {
            super.hideLoading()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (isSaveAccountAndPwd) {
            if (emailAccount.isNotEmpty()) {
                mBinding.etUsername.text = SpannableStringBuilder(emailAccount)
//                mBinding.etPassword.text = SpannableStringBuilder(pwdSaved)
                mBinding.etPassword.text = SpannableStringBuilder(DEFAULT_PWD_PLACEHOLDER)
            }
        }
        mBinding.cbLoginSavePwd.isChecked = isSaveAccountAndPwd
    }

    override fun onResume() {
        super.onResume()

        // 记录生命周期事件
        EnhancedLogger.lifecycle(
            tag = "LoginActivity",
            component = "LoginActivity",
            event = "onResume"
        )

        try {
            // 检查 MqttV5Service 是否在运行
            // 注意：在登录页面时，MQTT服务通常不应该运行
            // 如果检测到服务在运行，说明上次退出时服务没有正常关闭，需要强制清理
            val isMqttIsAlive = Base_CommonUtils.isServiceRunning(
                this,
                "com.newlink.building.main.service.MqttV5Service"
            )

            // 使用增强日志记录服务检查结果
            EnhancedLogger.service(
                tag = "LoginActivity",
                serviceName = "MqttV5Service",
                action = "CHECK_STATUS",
                status = if (isMqttIsAlive) "RUNNING (UNEXPECTED)" else "STOPPED (EXPECTED)"
            )

            if (isMqttIsAlive) {
                EnhancedLogger.w(
                    tag = "LoginActivity",
                    message = "⚠️ 异常状态: 登录页面发现MQTT服务仍在运行，执行清理操作"
                )
                // 发送退出消息来清理残留的服务
                EventBus.getDefault().post(MessageEvent(TYPE_APP_EXIT, true))
            } else {
                EnhancedLogger.success(
                    tag = "LoginActivity",
                    message = "✓ 正常状态: MQTT服务未运行（符合预期）"
                )
            }
        } catch (e: Exception) {
            EnhancedLogger.e(
                tag = "LoginActivity",
                message = "检查MQTT服务时发生异常: ${e.message}",
                throwable = e
            )
            // 异常时不影响正常登录流程
        }

        // 更新国家代码显示
        if (countryCode != mBinding.countryCodeBtn.text.toString()) {
            mBinding.countryCodeBtn.text = "+ $countryCode"
        }
    }

    private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
            if (isGranted) {
                // Permission is granted, proceed with notification-related actions
                NLog.e("[LoginActivity] !!! post_notification permission granted !!!! ")
            } else {
                // Permission is denied, show a message to the user or take appropriate action
                NLog.e("[LoginActivity] !!! post_notification permission denied !!!! ")
                showPermissionRationale()
            }
        }

    private fun showPermissionRationale() {
        val alertDialog = AlertDialog.Builder(this)
            .setMessage(getString(R.string.tips_go_setting_content_notify))
            .setPositiveButton(getString(R.string.app_need_allow_display_over_go)) { _, _ ->
                openAppSettings()
            }
            .setNegativeButton(getString(R.string.cancel_dialog_custom)) { _, _ ->
                finish()
            }
            .create()

        alertDialog.show()

        alertDialog.window?.run {
            attributes = attributes.apply {
                width = (windowManager.defaultDisplay.width * 0.95).toInt()
                gravity = Gravity.CENTER
            }
        }
    }

    private fun openAppSettings() {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
            data = Uri.fromParts("package", packageName, null)
        }
        startActivity(intent)
//        startActivityForResult(intent , object :OnActivityCallback{
//            override fun onActivityResult(resultCode: Int, data: Intent?) {
//                if (ActivityCompat.checkSelfPermission(
//                        this@LoginActivity,
//                        Manifest.permission.POST_NOTIFICATIONS
//                    ) != PackageManager.PERMISSION_GRANTED
//                ) {
//                    showPermissionRationale()
//                }
//            }
//
//        })
    }

    override fun showError(errorMsg: String) {
        // 错误处理时添加混淆
        Module_Obfuscation_ObfuscationHelper.onException(Exception(errorMsg))

        super.showError(errorMsg)
        mDialog.dismiss()
//        showToastImmediately("登录失败,请检查账号密码是否正确")
    }

    private fun checkIfEmailOrUserIdExists(input: String): Boolean {
        for ((index, item) in userAccountInfoList.withIndex()) {
            NLog.e("[LoginActivity]  checkIfEmailOrUserIdExists index:$index input:$input  userId:${item.userId} email:${item.email}")
            if (input == item.userId || input == item.email || input == item.mobile) {
                return true
            }
        }
        return false
    }

    private fun saveAccountInfo() {
        val email = userInfoData.email
        val mobile = userInfoData.mobile

        var userName = if (userInfoData.userCategory == 2) {
            if (email.isNotEmpty()) {
                email
            } else if (mobile.isNotEmpty()) {
                mobile
            } else {
                mEmailAccount
            }
        } else {
            mEmailAccount
        }

        if (mLoginDataFromRegister != null && pwdSaved.isEmpty()) {
            NLog.e("[LoginActivity]  from register and pwdSaved is null")
            return
        }

        userAccountInfoList = Module_Login_AccountMemoryUtils.saveAccountInfo(
            userName,
            userId.toString(),
            email,
            pwdSaved,
            mSelectCategory?.category ?: 1,
            userAccountInfoList,
            mobile
        )
    }

    private fun checkUserAccountEmpty(): Boolean {
        return userAccountInfoList.size == 1 && userAccountInfoList[0].timestamp == 0L
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray,
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == 0) {
            val granted =
                grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
            if (granted) {
                jumpToCapture()
                logInfo<Module_Login_LoginActivityNL>("CAMERA permission granted")
            } else {
//                showPermissionDialog()
//                checkCameraPermission()
                if (ActivityCompat.shouldShowRequestPermissionRationale(
                        this,
                        Manifest.permission.RECORD_AUDIO
                    )
                ) {
                    //拒绝
                    checkCameraPermission()
                } else {
                    openAppSettings()
                }
                logWarn<Module_Login_LoginActivityNL>("[LoginActivity] CAMERA permission denied")
            }
        }
    }

    private fun showPermissionDialog() {
        val mDialog = DialogUtil.getConfirmDialog(
            this,
            getString(R.string.permission_content_camera),
            { _, _ ->
                val intent = Intent()
                intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                val uri = Uri.fromParts("package", packageName, null)
                intent.data = uri
                startActivity(intent)
            }
        ) { _, _ -> }.show()
        mDialog.window?.run {
            attributes = attributes.apply {
                width = (windowManager.defaultDisplay.width * 0.95).toInt()
                gravity = Gravity.CENTER
            }
        }
    }


    private fun setSpannableStringView(
        context: Context,
        tv: TextView,
        userContent: String,
        policyContent: String,
        allContent: String,
    ) {
//        var str = context.getString(resId)
        var str = allContent
        str = str.replace("####", userContent)
        str = str.replace("****", policyContent)
        val index1 = str.indexOf(userContent)
        val index2 = str.indexOf(policyContent)


        spannableString = SpannableStringBuilder(str)

        spannableString?.apply {
            setSpan(
                userClickableSpan,
                index1,
                index1 + userContent.length,
                Spanned.SPAN_INCLUSIVE_EXCLUSIVE
            )
            setSpan(
                ForegroundColorSpan(ContextCompat.getColor(context, R.color.tablayout_indicator2)),
                index1,
                index1 + userContent.length,
                Spanned.SPAN_INCLUSIVE_EXCLUSIVE
            )
        }
        spannableString?.apply {
            setSpan(
                policyClickableSpan,
                index2,
                index2 + policyContent.length,
                Spanned.SPAN_INCLUSIVE_EXCLUSIVE
            )
            setSpan(
                ForegroundColorSpan(ContextCompat.getColor(context, R.color.tablayout_indicator2)),
                index2,
                index2 + policyContent.length,
                Spanned.SPAN_INCLUSIVE_EXCLUSIVE
            )
        }

        tv.text = spannableString
        tv.movementMethod = LinkMovementMethod.getInstance()
    }

    private fun jumpToLicense() {
        NLog.e("[LoginActivity] -> License View")
        val url =
            if (LocaleUtils.isSystemLocaleZh()) Base_Constant.PRIVACY_POLICY_URL else Base_Constant.PRIVACY_POLICY_URL_EN
        val title = getString(R.string.user_register_license_content)
//        FvlWebViewActivity.startSelf(BaseApplication.context , url , title)
        val intent = Intent(this, NL_WebViewActivityNL::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK
            putExtra("link", url)
            putExtra("title", title)
        }

        startActivity(intent)
    }

    /**
     * 二维码扫描结果回调
     * @param requestCode Int
     * @param resultCode Int
     * @param data Intent?
     */
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == RESULT_OK && requestCode == 100) {
            data?.let {
                mQRCodeLogin = true
                it.getStringExtra("data")?.let { token ->

                    //兼容Constant.KIT_REDIRECT_URL可能会更换的情况,扫出结果为URL格式截取相关设备信息
                    if (RegexUtils.checkURL(token)) {
                        val split = token.split("param=")
                        val deviceJson = if (split.size > 1) {
                            split[1]
                        } else {
                            ""
                        }

                        if (deviceJson.isEmpty()) {
                            showToast(getString(R.string.login_invalid_qr_code))
                            return
                        }

                        //如果用户未选择地址,提示用户
                        if (api_env_url.isEmpty()) {
                            showToast(getString(R.string.login_select_address_first))
                            return
                        }
//                        val deviceJson = token.substring(Constant.KIT_REDIRECT_URL.length)
//                        val kitDeviceDatas = mPresenter?.getKitDeviceDataFromQrcode(deviceJson)
//                        kitDeviceDatas?.let { it1 -> jumpToRegister(it1) }
                        jumpToRegister(Module_Phone_Base64Utils.decodeToString(deviceJson))
                    } else {
                        val parseUserAccount = mPresenter?.getUserNameFromQrcode(token)
                        if (parseUserAccount == null || parseUserAccount.size < 2) {
                            showToast(getString(R.string.login_invalid_qr_code))
                            return@let
                        }
                        val userid = parseUserAccount[0]
                        val pwdStr = parseUserAccount[1]

                        //数组第三个值为FcmsInfoData的id
                        if (parseUserAccount.size > 2 && mModuleLoginCheckUrlBeans.size > 0) {
                            //regionId对应fcms的id不是固定的,需要遍历获取下当前index
                            val regionId = parseUserAccount[2]
                            var index = -1
                            mModuleLoginCheckUrlBeans.forEach { item ->
                                if (item.id.toString() == regionId) {
                                    index = mModuleLoginCheckUrlBeans.indexOf(item)
                                }
                            }
                            //由于二维码里只携带regionId,调试地址需要从本地获取一下
                            if (index == -1) {
                                if (BuildConfig.DEBUG) {
                                    val fcmsInfos = parseFcmsInfoFromAssets()
                                    fcmsInfos.forEach { fcmsInfoData ->
                                        if (fcmsInfoData.id.toString() == regionId) {
                                            api_env_url = fcmsInfoData.url
                                            api_env = 1
                                        }
                                    }
                                }
                            } else {
                                api_env = index
                                api_env_url = mModuleLoginCheckUrlBeans[index].url
                            }

                            if (api_env_url.isEmpty()) {
                                showToast(getString(R.string.login_invalid_qr_code))
                                return
                            }
                            Base_Constant.BASE_URL = api_env_url
                            Base_RetrofitHelper.refreshDynamicBaseUrl()
                        }

//                    if (parseUserAccount.size == 3) {
//                        val server = parseUserAccount[2]
//                        Constant.BASE_URL = server
//                    }
                        mEmailAccount = userid!!
                        mPwdValue = pwdStr!!
                        NLog.e("[LoginActivity] login = > scan qrcode --> account = $mEmailAccount pwd =  $mPwdValue <不用加密>")
                        mPresenter?.loginFls(
                            mEmailAccount,
                            mPwdValue,
                            mSelectCategory!!.category,
                            false
                        )

                        needSavePwd = true
                    }
                }
            }
        }
    }

    private fun updateFlsServer() {
//        flsServer = Constant.BASE_URL
    }

    override fun onDestroy() {
        super.onDestroy()
        NLog.e("[LoginActivity] : onDestroy")
        if (spannableString != null) {
            spannableString?.clear()
            spannableString?.clearSpans()
            spannableString = null
        }
    }

    override fun onRequestSipSuccess(sipInfo: SipInfo) {
        NLog.e("[LoginActivity] >>> requestSipSuccess ...  $sipInfo")
        sipInforData = sipInfo
        serverType = sipInfo.serverType
        if (sipInfo.sipDisplay.isEmpty()) {
            sipInfo.sipDisplay = userInfoResp.name
        }
        isLogin = true

        ARouter.getInstance().build(Base_RouterPath.PATH_HOME)
            .withSerializable(NL_Key.REGISTER_SIP, sipInfo).navigation()
        finish()
    }

    override fun onGetVerifyCodeSuccess() {
        showToastImmediately(getString(R.string.get_verify_code_success))
        mBinding.btnSendVerify.start()
    }

    override fun onGetVerifyCodeFailed(msg: String?) {
        msg?.let {
            showToastImmediately(it)
        }
        mBinding.btnSendVerify.stop()
    }

    override fun onFcmsSuccess(data: MutableList<FcmsInfoData>) {
        NLog.e("[LoginActivity] >>> onFcmsSuccess 收到 ${data.size} 个服务器: $data")
        for (item in data) {
            mModuleLoginCheckUrlBeans?.add(
                Module_Login_CheckUrlBean(
                    item.id,
                    item.name,
                    item.url,
                    0,
                    item.url == api_env_url
                )
            )
        }
        val customBean = parseCustomRegionBean()
        mModuleLoginCheckUrlBeans?.add(customBean)

        // 处理默认选择逻辑
        if (api_env_url == Base_Constant.BASE_XLINK_URL && api_env_url_custom.isNotEmpty()) {
            // 使用自定义地址（首次安装或用户选择了自定义）
            api_env = mModuleLoginCheckUrlBeans.size - 1  // 自定义选项是最后一个
            mBinding.tvSelectAddress.text = getString(R.string.login_region_custom_fcms_title)
        } else if (api_env != -1 && api_env < mModuleLoginCheckUrlBeans.size - 1) {
            // 用户之前选择了预设的服务器选项
            mBinding.tvSelectAddress.text = mModuleLoginCheckUrlBeans[api_env].displayName
        } else {
            // 默认情况，显示自定义
            api_env = mModuleLoginCheckUrlBeans.size - 1
            mBinding.tvSelectAddress.text = getString(R.string.login_region_custom_fcms_title)
        }

        // 自定义地址需要填充参数
        if (api_env == mModuleLoginCheckUrlBeans.size - 1) {
            val customUrlBean = mModuleLoginCheckUrlBeans[api_env]
            customUrlBean.url = if (api_env_url_custom.isNotEmpty()) api_env_url_custom else api_env_url
            customUrlBean.isChecked = true
        }
        //如果fmcs地址数量为1 默认选中地址
        setDefaultEnv(data)
    }

    private fun setDefaultEnv(data: MutableList<FcmsInfoData>) {
        if (api_env_url.isEmpty() && data.size == 1) {
            api_env = 0
            api_env_url = data[0].url
            Base_Constant.BASE_URL = api_env_url
            mBinding.tvSelectAddress.text = data[0].name
            Base_RetrofitHelper.refreshDynamicBaseUrl()
        }
    }

    override fun onFcmsLoadLocalFirst() {
        NLog.e("[LoginActivity] >>> onFcmsLoadLocalFirst, 优先使用本地默认地址列表")
        try {
            val localFcmsData = parseFcmsInfoFromAssets()
            if (localFcmsData.isNotEmpty()) {
                onFcmsSuccess(localFcmsData)
            } else {
                showToastImmediately(R.string.login_load_fcms_address_failed)
            }
        } catch (e: Exception) {
            NLog.e("[LoginActivity] >>> parseFcmsInfoFromAssets failed: ${e.message}")
            showToastImmediately(R.string.login_load_fcms_address_failed)
        }
    }

    override fun onFcmsFail() {
        NLog.e("[LoginActivity] >>> onFcmsFail, 网络请求失败，但已有本地数据，无需处理")
        // 由于已经先加载了本地数据，这里网络失败时不需要额外处理
    }

    override fun onGetAgreementSuccess(data: PolicyAgreementData?) {
        mPolicyAgreementData = data

        // 使用增强日志记录网络请求成功
        EnhancedLogger.json(
            tag = "LoginActivity",
            title = "获取协议信息成功",
            jsonString = data?.let { "Agreement: ${it.agreementPath}, Policy: ${it.policyPath}" }
        )

        data?.let {
            userClickableSpan.setUrl(it.agreementPath)
            policyClickableSpan.setUrl(it.policyPath)

            // 记录空值情况用于调试
            if (it.agreementPath.isNullOrEmpty()) {
                EnhancedLogger.w("LoginActivity", "协议路径为空: agreementPath is null or empty")
            }
            if (it.policyPath.isNullOrEmpty()) {
                EnhancedLogger.w("LoginActivity", "隐私政策路径为空: policyPath is null or empty")
            }
        }
    }

    override fun onLoginFail(msg: String?) {
        if (mQRCodeLogin) {
            showToastImmediately(R.string.login_invalid_qr_code)
        } else {
            showToastImmediately(msg!!)
        }

        if (mDialog != null) {
            mDialog.dismiss()
        }
    }

    override fun onGetKcpInfoSuccess(data: KcpInfoData) {
        //47.102.210.208
        NLog.e("[LoginActivity] 获取到KCP信息, 下一步进入主页面 : $data")
        kcpDestDeviceId = data.destDevId
        cUserId = data.devId
        kcpInfoData = data
//        kcpConnectId = mPresenter?.connectKcp(data)!!
    }

    override fun onGetAppConfigSuccess(data: AppConfigData) {
        appCfgProgress = false
        isLogin = true
        NLog.e("[LoginActivity] onGetMqttInfoSuccess : $data")

        data.mqtt?.let { mqttDataCache = it }
        data.cfg?.let {
            agoraId = it.aid
            agoraAppId = it.appId
        }
        NLog.e("[LoginActivity] onGetMqttInfoSuccess 22 : $mqttDataCache")
        tokenStart = System.currentTimeMillis()
//        App.rinoManager.initRinoSDK(agoraId.toString())
        if (mLoginDataFromRegister == null) {
            ARouter.getInstance().build(Base_RouterPath.PATH_HOME)
                .withSerializable(NL_Key.EXTRA_MQTT, data.mqtt).navigation()
            finish()
        }
    }

    override fun onKcpConnectSuccess() {
        NLog.e("[LoginActivity] KCP 模块链接成功")
        val sipRequest = SipRequest(
            Base_KcpRquestType.TYPE_SIP_REGISTER, accessToken, cUserId,
            SipRequestBody(Base_RegisterDeviceType.APP.code, userInfoResp.name)
        )
        mPresenter?.requestSipRegister(sipRequest)
    }

    override fun onKcpConnectFailed(status: Int) {
//        try {
//            val resId = RntcErrorCode.getResIdByCode(status)
//            showToast(getString(R.string.kcp_connect_failed_case, status, getString(resId)))
//        } catch (e: Exception) {
//            e.printStackTrace()
//        }
    }

    override fun onKcpConnectLoopFailed() {
        NLog.e("[LoginActivity] connectKcpFailed ... ")
        hideLoading()
    }

    override fun onKcpFail() {
        showToastImmediately("登录失败,请检查你的账号密码是否正确！")
    }

    override fun onAppConfigFail() {
        appCfgProgress = false
        showToastImmediately("获取App Config配置失败！")
    }

    override fun onGetUserInfoSuccess(data: UserInfoData) {
        NLog.e("[LoginActivity] 获取到用户信息,  : $data")
        userInfoData = data
        projectId = userInfoData.prjId
        isPrimaryAccount = data.userType == 1
        if (mLoginDataFromRegister == null && mWayToLogin == ACCOUNT_PASSWORD_LOGIN) {
            saveAccountInfo()
        }
        NLog.e("[LoginActivity] 开始i请求 MQTT 信息,  ")
        mPresenter?.getAppConfig(accessToken)
    }

    override fun onGetUserInfoFailed() {
        NLog.e("[LoginActivity] 获取用户信息失败 ")
    }

    override fun onGetTokenSuccess(token: String, userId: Long) {
        logDebug<Module_Login_LoginActivityNL>("getTokenSuccess  token:$token  userId:$userId  mPwdValue:$mPwdValue")

        mSelectCategory?.let {
            userCategory = it.category
        }
        appCfgProgress = true
        emailAccount = mEmailAccount
        if (mPwdValue != DEFAULT_PWD_PLACEHOLDER) {

            if (mLoginDataFromRegister == null) {
                pwdSaved = if (!needSavePwd) {
                    Md5Crypt.md5(mPwdValue)
                } else {
                    mPwdValue
                }
            }

        }
        NLog.e("[LoginActivity] 登陆成功保存账户信息:::: 账号: ..$emailAccount.....密码: .$pwdSaved ")
        updateFlsServer()
        accessToken = token
        this.userId = userId

        mPresenter?.getUserInformation(token, userId)
        // 阿里云服务绑定 Account
        val uId = userId.toString()
        NLog.e("PushService 绑定用户ID : $uId")
        val mPushService = PushServiceFactory.getCloudPushService()
        mPushService.bindAccount(uId, object : CommonCallback {
            override fun onSuccess(s: String?) {
                NLog.e(">>> PushService onSuccess: $s <<<< ")
                mPushService.turnOnPushChannel(object : CommonCallback {
                    override fun onSuccess(p0: String?) {
                        NLog.e(">>> PushService onSuccess: $p0 111111111111 <<<< ")

                        mPushService.checkPushChannelStatus(object : CommonCallback {
                            override fun onSuccess(p0: String?) {
                                NLog.e(">>> PushService onSuccess: $p0 222222222 <<<< ")
                            }

                            override fun onFailed(p0: String?, p1: String?) {
                                NLog.e(">>> PushService onFailed: $p0 2222222<<<< ")
                            }
                        })
                    }

                    override fun onFailed(p0: String?, p1: String?) {
                        NLog.e(">>> PushService onFailed: $p0 111111111111<<<< ")
                    }

                })

            }

            override fun onFailed(errorCode: String, errorMsg: String) {
                NLog.e("PushService onFailed: errorCode:" + errorCode + "errorMsg:" + errorMsg)
            }
        })

        CrashReport.setUserId(userId.toString())

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onMsgEventReceived(event: MessageEvent) {
        when (event.msgType) {
            TYPE_REGISTER_SUCCESS -> {
                val loginResponseData = event.msgContent as LoginResponseData
                mLoginDataFromRegister = loginResponseData
                onGetTokenSuccess(loginResponseData.access_token, loginResponseData.userId)
                NLog.e("TYPE_REGISTER_SUCCESS ${loginResponseData.userId} - ${loginResponseData.access_token}")
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onResetPwdEvent(event: SetKitPwdEvent) {
        if (event.tag) {
            if (mLoginDataFromRegister != null && mqttDataCache != null) {
//                pwdSaved = event.md5Pwd
//                saveAccountInfo()
                ARouter.getInstance().build(Base_RouterPath.PATH_HOME)
                    .withSerializable(NL_Key.EXTRA_MQTT, mqttDataCache).navigation()
                finish()
            }
        }
    }

    private fun checkCameraPermission() {
        val message =
            getString(R.string.common_permission_camera_message, getString(R.string.app_name_smart))

        CustomMessageDialog(this).setTitle(getString(R.string.common_permission_title))
            .setMessage(message)

            .setNegativeButton(
                getString(R.string.cancel_dialog_custom)
            ) { dialog ->
                dialog.dismiss()
                showToast(getString(R.string.common_permission_cancel_alert))
            }
            .setPositiveButton(
                getString(R.string.common_permission_to_setting)
            ) { dialog ->
                requestPermissions(arrayOf(Manifest.permission.CAMERA), 0)
                dialog.dismiss()
            }.show()
    }
}
